package com.right.near.business.service.impl;

import com.right.near.business.model.ao.LoginAO;
import com.right.near.business.model.dto.UserDetailDTO;
import com.right.near.business.model.vo.LoginVO;
import com.right.near.business.service.IAuthService;
import com.right.near.common.constants.NumberConstants;
import com.right.near.common.constants.RedisConstants;
import com.right.near.common.exception.BusinessException;
import com.right.near.common.utils.DateUtil;
import com.right.near.common.utils.UuidUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * 认证服务实现类
 *
 * @author: Star.zhu
 * @date: 2022/8/12
 */
@Slf4j
@Service
@AllArgsConstructor
public class AuthServiceImpl implements IAuthService {
    private final RedisTemplate redisTemplate;

    private final AuthenticationManager authenticationManager;

    /**
     * 账号密码登陆认证
     *
     * @param ao 登陆数据
     * @return LoginVo
     */
    @Override
    public LoginVO userLogin(LoginAO ao) {
        LoginVO vo = new LoginVO();
        try {
            // 解码
//            Base64.Decoder decoder = Base64.getDecoder();
//            String password = new String(decoder.decode(ao.getPassword()), StandardCharsets.UTF_8);
            //生成token
            String token = UuidUtil.createUuid();
            final Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(ao.getUsername(), ao.getPassword()));
            //存储认证信息
            SecurityContextHolder.getContext().setAuthentication(authentication);
            UserDetailDTO userDetail = (UserDetailDTO) authentication.getPrincipal();
            //存储token
            ValueOperations<String, UserDetailDTO> valueOperations = redisTemplate.opsForValue();
            valueOperations.set(RedisConstants.AUTH_TOKEN.concat(token), userDetail, NumberConstants.FOUR_LONG, TimeUnit.HOURS);
            vo.setRole(userDetail.getRoles());
            vo.setToken(token);
            vo.setExpire(Objects.isNull(userDetail.getExpire()) ? null : DateUtil.diffDate(userDetail.getExpire()) - 1);
        } catch (CredentialsExpiredException e) {
            log.error("登陆认证失败，账号已过期：", e);
            throw new BusinessException("账号已过期");
        } catch (LockedException e) {
            log.error("登陆认证失败，账号已锁定：", e);
            throw new BusinessException("账号已锁定");
        } catch (Exception e) {
            log.error("登陆认证失败：", e);
            throw new BusinessException("账户或密码错误");
        }
        return vo;
    }

}
